package containerlogistik.implementation;

import containerlogistik.interfaces.Acceleration;
import containerlogistik.interfaces.Level;
import static containerlogistik.implementation.Values.*;

public class LevelOfPedal extends AbstractValue<Level> implements Level {

    private final int level;
    private final static int MAX_LEVEL = 100;
    private final static int MIN_LEVEL = -100;
    private final static int ZERO_LEVEL = 0;

    private LevelOfPedal(int level) {
        this.level = level;
    }

    static Level valueOf(int level) {
        return new LevelOfPedal(level);
    }

    public static boolean isInRange(int i) {
        return (i >= MIN_LEVEL && i <= MAX_LEVEL);
    }

    @Override
    public boolean isZero() {
        return (this.equals(ZERO_LEVEL));
    }

    @Override
    public boolean isValid() {
        return isInRange(this.level);
    }

    @Override
    public double g() {
        return this.level * LEVEL_IN_G;
    }

    @Override
    public int level() {
        return this.level;
    }

    @Override
    public String toString() {
        return "LevelOfPedal{" + "g=" + this.g() + '}';
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (!(obj instanceof Level)) return false;
        return this.compareTo((Level)obj) == 0;
    }

    @Override
    public int hashCode() {
        return hashDouble(this.level());
    }

    @Override
    public int compareTo(Level o) {
        return Double.compare(this.level(), o.level());
    }

    @Override
    public Level add(Level value) {
        final Level newLevel = levelOfPedal(this.level() + value.level());
        return (isInRange(newLevel.level())) ? levelOfPedal(newLevel.level()) : levelOfPedal(MAX_LEVEL);
    }

    @Override
    public Level sub(Level value) {
        final Level newLevel = levelOfPedal(this.level() - value.level());
        return (isInRange(newLevel.level())) ? newLevel : levelOfPedal(MIN_LEVEL);
    }

    @Override
    public Level mul(double factor) {
        final Level newLevel = levelOfPedal((int)(this.level() * factor));
        return (isInRange(newLevel.level())) ? newLevel : levelOfPedal(MAX_LEVEL);
    }

    @Override
    public Level div(double factor) {
        final Level newLevel = levelOfPedal((int)(this.level() / factor));
        return (isInRange(newLevel.level())) ? newLevel : levelOfPedal(MIN_LEVEL);
        
    }

    @Override
    public Level inverse() {
        return Values.levelOfPedal(-this.level());
    }

    @Override
    public double div(Level value) {
        return (this.level() / value.level());
    }

    @Override
    public Acceleration mul(Acceleration acc) {        
        return accelerationInMs2(this.g() * acc.ms2());
    }
}